package com.ggb.reactive.controller.user

import com.ggb.reactive.domain.vo.DishVO
import com.ggb.reactive.extension.log
import com.ggb.reactive.model.Result
import com.ggb.reactive.repository.DishFlavorRepository
import com.ggb.reactive.repository.DishRepository
import io.swagger.v3.oas.annotations.Operation
import io.swagger.v3.oas.annotations.tags.Tag
import lombok.RequiredArgsConstructor
import org.springframework.beans.BeanUtils
import org.springframework.data.redis.core.ReactiveRedisTemplate
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController
import reactor.core.publisher.Mono
import reactor.core.scheduler.Schedulers
import reactor.kotlin.core.publisher.switchIfEmpty

@RestController("userDishController")
@RequestMapping("/user/dish")
@RequiredArgsConstructor
@Tag(name = "用户-菜品管理")
class DishController(
    private val dishRepository: DishRepository,
    private val dishFlavorRepository: DishFlavorRepository,
    private val reactiveRedisTemplate: ReactiveRedisTemplate<String, Any>
) {

    @GetMapping("/list")
    @Operation(summary = "获取菜品列表")
    fun list(categoryId: Long): Mono<Result<List<DishVO>>> {
        log.info("categoryId {}", categoryId)
        val key = "dish_$categoryId"
        // 在这段代码中，我们使用了 flatMap 替换了 map，因为 map 仅在值不为 null 时才会执行，而 flatMap 则可以处理 null 值。
        // 这样，即使 get 操作返回 null，我们仍然能够继续执行后续的逻辑。
        return reactiveRedisTemplate.opsForValue().get(key)
            .flatMap { cachedDishes ->
                // 如果从缓存中获取到了数据
                log.info("从缓存中获取菜品列表{}", cachedDishes)
                Mono.just(cachedDishes as List<DishVO>)
            }
            .switchIfEmpty {
                // 如果缓存中没有数据，则执行默认逻辑
                dishRepository.findDishByCategoryId(categoryId)
                    .flatMap { dish ->
                        dishFlavorRepository.findDishFlavorByDishId(dish.id!!)
                            .collectList()
                            .map { flavors ->
                                val dishVO = DishVO()
                                BeanUtils.copyProperties(dish, dishVO)
                                dishVO.flavors = if (flavors.isEmpty()) emptyList() else flavors
                                // 处理redis时间转换的bug
                                dishVO
                            }
                    }
                    .collectList()
                    .publishOn(Schedulers.boundedElastic())
                    .doOnNext { dishVOs ->
                        val dishes = dishVOs.map {
                            it.updateTime = null
                            it
                        }
                        reactiveRedisTemplate.opsForValue().set(key, dishes).subscribe()
                    }
            }
            .map { dishVOs -> Result.success(dishVOs) }
            .switchIfEmpty(Mono.just(Result.success(emptyList())))

    }
}